{
 "metadata": {
  "name": ""
 },
 "nbformat": 3,
 "nbformat_minor": 0,
 "worksheets": [
  {
   "cells": [
    {
     "cell_type": "heading",
     "level": 1,
     "metadata": {},
     "source": [
      "Pr\u00e0ctiques de Nous Usos de la Inform\u00e0tica"
     ]
    },
    {
     "cell_type": "heading",
     "level": 2,
     "metadata": {},
     "source": [
      "Naive Bayes i Classificaci\u00f3"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "<b>Qu\u00e8 s\u2019ha de fer?</b><br>\n",
      "Volem classificar blogs corresponents a militants de quatre partits pol\u00edtics segons la seva ideologia. Per fer-ho farem servir les seves entrades RSS o Atom. A partir de les seves entrades crearem un vector de caracter\u00edstiques que ens descrigui el contingut del blog. Finalment desenvoluparem un classificador probabil\u00edstic del tipus Naive Bayes que ens permeti identificar la ideologia d'un nou blog donat la seva descripci\u00f3 en les caracter\u00edstiques escollides.<br>\n",
      "\n",
      "<b>Quina \u00e9s la idea del sistema de classificaci\u00f3 que s\u2019ha de desenvolupar?</b><br>\n",
      "El classificador \u00e9s un concepte de l'aprenentatge autom\u00e0tic supervisat. L'objectiu del classificador \u00e9s donat un vector de caracter\u00edstiques que descriuen els objectes que es volen classificar indicar a quina categoria o classe pertanyen d'entre un conjunt predeterminat. El proc\u00e9s de classificaci\u00f3 consta de dues parts: (a) el proc\u00e9s d'aprenentatge i (b) el proc\u00e9s d'explotaci\u00f3 o testeig. El proc\u00e9s d'aprenentatge rep exemples de parelles (x,y) on x s\u00f3n les caracter\u00edstiques, usualment nombres reals, i y \u00e9s la categoria a la que pertanyen. Aquest conjunt se'l coneix com a conjunt d'entrenament i ens servir\u00e0 per trobar una funci\u00f3 y=h(x) que donada una x m'indiqui quina \u00e9s la y. Per altra banda el proc\u00e9s de testeig aplica la funci\u00f3 h(x) apresa a l'entrenament a una nova descripci\u00f3 per veure quina categoria li correspon.</br>\n",
      "\n",
      "<b>Classificaci\u00f3 i llenguatge natural</b><br>\n",
      "La descripci\u00f3 dels exemples en caracter\u00edstiques \u00e9s el punt m\u00e9s cr\u00edtic de tot sistema d'aprenentatge autom\u00e0tic. Una de les representacions m\u00e9s simples per tal de descriure un text \u00e9s la representaci\u00f3 bag-of-words. Aquesta representaci\u00f3 converteix un text en un vector de N paraules. Consisteix en seleccionar un conjunt d'N paraules i per cada paraula contar quants cops apareix en el text. Una versi\u00f3 alternativa d'aquest proc\u00e9s pot ser simplement indicar si apareix o no en el text.\n",
      "\n",
      "<b>Exemple.</b>\n",
      "Imaginem que tenim 4 texts que pertanyen nom\u00e9s a dues categories y={'ERC, 'ICV'}, podr\u00edem seleccionar les seg\u00fcents paraules per tal de distingir les dues categories x={'nuclear', 'verd', 'ecologia', 'independ\u00e8ncia', 'autonomia', 'refer\u00e8ndum'}\n",
      "\n",
      "<table border=\"1\">\n",
      "<tr>\n",
      "<td></td>\n",
      "<td>nuclear</td>\n",
      "<td>verd</td>\n",
      "<td>ecologia</td>\n",
      "<td>independ\u00e8ncia</td>\n",
      "<td>autonomia</td>\n",
      "<td>refer\u00e8ndum</td>\n",
      "</tr>\n",
      "<tr>\n",
      "<td>tesxt 1('ERC')</td>\n",
      "<td>0</td>\n",
      "<td>0</td>\n",
      "<td>0</td>\n",
      "<td>1</td>\n",
      "<td>2</td>\n",
      "<td>3</td>\n",
      "</tr>\n",
      "<tr>\n",
      "<td>tesxt 2('ERC')</td>\n",
      "<td>0</td>\n",
      "<td>1</td>\n",
      "<td>0</td>\n",
      "<td>1</td>\n",
      "<td>2</td>\n",
      "<td>3</td>\n",
      "</tr>\n",
      "<tr>\n",
      "<td>tesxt 1('ICV')</td>\n",
      "<td>1</td>\n",
      "<td>3</td>\n",
      "<td>1</td>\n",
      "<td>0</td>\n",
      "<td>1</td>\n",
      "<td>0</td>\n",
      "</tr>\n",
      "<tr>\n",
      "<td>tesxt 2('ICV')</td>\n",
      "<td>2</td>\n",
      "<td>1</td>\n",
      "<td>2</td>\n",
      "<td>0</td>\n",
      "<td>0</td>\n",
      "<td>0</td>\n",
      "</tr>\n",
      "</table>\n",
      "\n",
      "<br>\n",
      "amb aquesta representaci\u00f3 el text 2, corresponent a la categoria 'ERC', quedaria representat pel vector num\u00e8ric (0,1,0,1,2,3). Si fem servir la representaci\u00f3 alternativa tindr\u00edem (0,1,0,1,1,1) que indica la pres\u00e8ncia de les paraules. Si la descripci\u00f3 \u00e9s adient s'espera que les categories es puguin distingir amb facilitat.\n",
      "<br><br>\n",
      "<b>El classificador Na\u00efve Bayes.</b><br>\n",
      "Un cop tenim una representaci\u00f3 necessitem un proc\u00e9s d'aprenentatge que ens permeti passar de la descripci\u00f3 a una categoria. En aquesta pr\u00e0ctica farem servir el classificador Na\u00efve Bayes. Aquest classificador forma part de la fam\u00edlia de classificadors probabil\u00edstics. La sortida d'un classificador probabil\u00edstic \u00e9s un valor de probabilitat donat un exemple per cadascuna de les categories. La decisi\u00f3 final correspon a la categoria amb m\u00e9s probabilitat. Per exemple, amb la descripci\u00f3 anterior esperem que la sortida sigui de l'estil,<br>\n",
      "$$p( y = 'ERC' | x = (0,1,0,1,1,1)) = 0.6$$\n",
      "$$p( y = 'ICV' | x = (0,1,0,1,1,1)) = 0.4$$\n",
      "\n",
      "<br>\n",
      "Els classificadors probabilistics Bayesians es basen en el teorema de Bayes per realitzar els c\u00e0lculs per trobar la probabilitat condicionada. Es basen en el teorema de Bayes que diu:<br>\n",
      "\n",
      "$$ p(x,y) = p(x|y)p(y) = p(y|x)p(x)$$\n",
      "<br>\n",
      "d'on podem extreure que: <br>\n",
      "$$ p(y,x) = \\frac{p(x|y)p(y)}{p(x)}$$\n",
      "<br>\n",
      "\n",
      "\n",
      "En molts casos p(y) i p(x) s\u00f3n desconeguts i es consideren equiprobables. Per tant, la\n",
      "decisi\u00f3 es simplifica a:\n",
      "<br>\n",
      "$$ p(y|x) = c \u00b7 p(x|y)$$\n",
      "\n",
      "<br>\n",
      "Les deduccions fins a aquest punt s\u00f3n v\u00e0lides per la majoria de classificadors Bayesians. Na\u00efve Bayes es distingeix de la resta perqu\u00e8 imposa una condici\u00f3 encara m\u00e9s restrictiva. Considerem x=(x1,x2,x3,...,xN) un conjunt d'N variables aleat\u00f2ries. Na\u00efve Bayes assumeix que totes elles s\u00f3n independents entre elles i per tant podem escriure:\n",
      "<br>\n",
      "$$p(x_1,x_2,...,x_N | y) = p(x_1|y)p(x_2|y)...p(x_N|y)$$\n",
      "\n",
      "<br>\n",
      "Per tant en el nostre cas es pot veure com:\n",
      "<br>\n",
      "$$p(y='ERC'|x=(0,1,0,1,1,1)) = p(x_1=0|y='ERC')p(x_2=1|y='ERC')...p(x_6=1|y='ERC')$$\n",
      "\n",
      "<br>\n",
      "Podem interpretar l'anterior equaci\u00f3 de la seg\u00fcent forma: La probabilitat de que el document descrit pel vector de caracter\u00edstiques (0,1,0,1,1,1) es proporcional al producte de la probabilitat que la primera paraula del vector no aparegui en els documents de la categoria 'ERC' per la probabilitat que la segona paraula s\u00ed aparegui als documents d''ERC', etc.\n",
      "\n",
      "<br>\n",
      "<b>Estimant les probabilitats marginals condicionades</b>\n",
      "L'\u00faltim pas que ens queda \u00e9s trobar el valor de les probabilitats condicionades. Fem servir la representaci\u00f3 de 0 i 1's indicant que la paraula no apareix (0) o s\u00ed apareix (1) al document. Per trobar el valor de la probabilitat condicionada farem servir una aproximaci\u00f3 freq\u00fcentista a la probabilitat. Aix\u00f2 vol dir que calcularem la freq\u00fc\u00e8ncia d'aparici\u00f3 de cada paraula per a cada categoria. Aquest c\u00e0lcul es fa dividint el nombre de documents de la categoria en que apareix la paraula pel nombre total de documents d'aquella categoria. En l'exemple anterior, p(x2=apareix 'verd'|y='ERC')=1/2 mentres que p(x2=apareix 'verd'|y='ICV')=2/2.\n",
      "<br>\n",
      "$$p(x_2 = 1 | y = 'ERC')= \\frac{A}{B} $$\n",
      "<br>\n",
      "on A \u00e9s el n\u00famero de blocs de 'ERC' on apareix la paraul 'verd' i B \u00e9s el n\u00famero de bloc de 'ERC'.\n",
      "\n",
      "\n",
      "<b>PROBLEMES: </b><br>\n",
      "<b> * El problema de la probabilitat 0</b>\n",
      "Si us fixeu a l'anterior exemple la probabilitat <b>p(x2=no apareix 'verd' | y='ICV')</b> \u00e9s 0 !! Aix\u00f2 vol dir, que si no apareix la paraula 'verd' al blog no pot ser d''ICV' !! No sembla raonable que es penalitzi totalment l'aparici\u00f3 d'aquesta categoria pel fet que una \u00fanica paraula aparegui o no al text. Per tant el que s'acostuma a fer \u00e9s donar una baixa probabilitat en comptes de zero. Una de les possibles solucions es fer servir la correcci\u00f3 de Laplace. Seguint l'exemple anterior la correcci\u00f3 de Laplace \u00e9s\n",
      "\n",
      "<br>\n",
      "$$p(x_2=1 | y = 'ERC' ) = \\frac{A+1}{B+M}$$ \n",
      "on M \u00e9s el nombre de catergories\n",
      "\n",
      "<b> * El problema del 'underflow'</b>\n",
      "L'elecci\u00f3 de les paraules que formen el vector de caracter\u00edstiques \u00e9s un pas cr\u00edtic. En funci\u00f3 de quan bona \u00e9s aquesta descripci\u00f3 millor funcionar\u00e0 el sistema. Tot i que us deixem a vosaltres la pol\u00edtica de creaci\u00f3 del vector de caracter\u00edstiques us donem una d'exemple. Per saber quines paraules fer servir podeu seleccionar de totes les paraules de tots els blogs aquelles que apareixen entre en un 10 i un 50 percent dels blogs (sense tenir en compte la categoria). Podeu experimentar a variar aquests valors."
     ]
    },
    {
     "cell_type": "raw",
     "metadata": {},
     "source": [
      "Els fitxers python feedparser.py i generatefeedvector.py. El fitxer feedparser.py ens permet recuperar la informaci\u00f3 proporcionada per sistemes de feed com RSS o Atom.  \n",
      "El fitxer generatefeedvector.py proporciona utilitats b\u00e0siques per dividir el resultat de l'anterior en paraules eliminant tags d'HTML, traduint car\u00e0cters unicode i HTML corresponents al sistema de puntuaci\u00f3 catal\u00e0. \n",
      "A m\u00e9s trobareu el fitxer blogs.txt que cont\u00e9 una llista de blogs amb el seg\u00fcent format:  ID | Partit | Nom | URL"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "import math\n",
      "import csv\n",
      "import generatefeedvector as generate\n",
      "import pandas as pd\n",
      "import numpy as np\n",
      "\n",
      "\n",
      "#Retorna un diccionari amb la seguent estricutra: {id_blog:(nom_politic,{paraula1:numAparicions;paraule2:numAparicision,...})}\n",
      "def download_text(df):\n",
      "    dicc={}\n",
      "    invalid_blogs=[]\n",
      "    #recorremos la lista con toda la informacion de todos los blogs\n",
      "    urls=list(df['url'])\n",
      "    for i in df.index:\n",
      "        try:\n",
      "            dicc[i]=generate.getwordcounts(df.ix[i]['url'])\n",
      "        except:\n",
      "            invalid_blogs.append(df.index[i])\n",
      "            print \"Link incorrecte, blog\", df.ix[i]['nom']\n",
      "    print \"\\nLectura dels blogs finalizada.\\n\",\n",
      "    return dicc,invalid_blogs    "
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 1
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# CREACIO DEL DATAFRAME \n",
      "unames = ['id_blog', 'partit_politic', 'nom', 'url']\n",
      "df = pd.read_table('blogs.dat',sep='::', header=None, names=unames)\n",
      "\n",
      "# EXEMPLE DE COM BAIXR D'UN CONJUNT DE BLOGS\n",
      "data_blogs,invalid_blogs=download_text(df)\n",
      "# EXEMPLE DE COM ELIMINAR AQUELLS BLOGS QUE NO S'HA POGUT ACCEDIR\n",
      "df=df.drop(invalid_blogs)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "Link incorrecte, blog Pia Bosch\n",
        "Link incorrecte, blog"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        " Xavier Tornafoch\n",
        "\n",
        "Lectura dels blogs finalizada.\n"
       ]
      }
     ],
     "prompt_number": 2
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "<b>Exercici 1 </b> Escriure una funci\u00f3 <b>count_blogs(dataframe)</b> que retorni el nombre total de blocs. "
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "#Retorna el n\u00famero total de blogs. \n",
      "def count_blogs(df):\n",
      "    return len(df)\n",
      "print count_blogs(df)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "119\n"
       ]
      }
     ],
     "prompt_number": 25
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "<b>Exercici 2:</b> Escriure una funci\u00f3 <b>count_party_blogs(dataframe)</b> que compte quants blogs hi ha per cadascun dels partits."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "#Retorna una Series que cont\u00e9 el n\u00famero de blogs per partit pol\u00edtic\n",
      "def count_blogs_party(df):\n",
      "    return df.groupby('partit_politic')['partit_politic'].count()\n",
      "\n",
      "print count_blogs_party(df)\n"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "partit_politic\n",
        "CIU               32\n",
        "ERC               29\n",
        "ICV               25\n",
        "PSC               33\n",
        "dtype: int64\n"
       ]
      }
     ],
     "prompt_number": 26
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 9
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "<b>Exercici 3:</b> Escriure una funci\u00f3 <b>count_words(dataframe,data_blogs)</b> que que retorni un diccionari amb totes les paraules que han aparescut en els blogs, indicant la quantitat de cops i el nombre de blogs on ha sortit.\n",
      "<br>Possible format sortida: {word :  {freq: valor;n_cops: valor}}"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# Aquesta funci\u00f3 ha de contruir un diccionari que contingui totes les paraules que s'han trobat indicant \n",
      "# el total de cops que ha aparescut i el nombre de blogs on apareix\n",
      "def count_words(df,data_blogs):\n",
      "    dicc={}\n",
      "    for item in df.index:\n",
      "        \n",
      "        for word in data_blogs[item][1]:\n",
      "            \n",
      "            if (dicc.has_key(word)):\n",
      "                #si la paraula ja existeix dins el diccionari, augmentem la seva frequencia d'aparicio\n",
      "                dicc[word][\"freq\"]+=data_blogs[item][1][word]\n",
      "                #tamb\u00e9 augmentem el n\u00famero de blogs on la paraula apareix\n",
      "                dicc[word][\"n_blogs\"]+=1\n",
      "            else:\n",
      "                #si la paraula encara no estava dins el diccionari, creem una entrada per a ella\n",
      "                dicc[word]={\"freq\":data_blogs[item][1][word], \"n_blogs\":1}\n",
      "    return dicc"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 31
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 34
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "<b>Exercici 4:</b> escriure una funci\u00f3 <b>count_words_party(dataframe,dicc_text)</b> que retorna un diccionari que conte el nombre de cops que ha aparescut cada paraula i el n\u00famero de blogs on  ha aparescut. Aquesta informaci\u00f3 ha de ser dividida en els diferents gruos pol\u00edtics.\n",
      "<br>Possible format sortida: {Partit_potilit :  {word :  {freq: valor;n_cops: valor} } } "
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "#Contem la freq\u00fc\u00e8ncia de cadascuna de les paraules per un partit determinat\n",
      "def count_words_party(df,dicc_text):\n",
      "    partits=set(df['partit_politic'])\n",
      "    dicc={}\n",
      "    for partit in partits:\n",
      "        dicc[partit]=count_words(df[df['partit_politic']==partit],data_blogs)\n",
      "    return dicc\n",
      "\n",
      "words_partits= count_words_party(df,data_blogs)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 36
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "<b>Exercici 5:</b> Calcular amb la funci\u00f3 <b>topNword(df,words_partits,N)</b> quines son les N paraules m\u00e9s representatives (les que apareixen amb m\u00e9s freq\u00fc\u00e8ncia) de cadascun dels partits. Retorneu un diccionari amb els seg\u00fcent format: {PSC: llista_top_words_PSC; ERC: llista_top_words_ERC;...}\n",
      "<br>Teniu en compte que tamb\u00e9 haureu de filtrar aquelles paraules que apareixen en la majoria de blogs i les que \u00fanicament apareixen en un conjunt molt petit dels blogs.\n"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "#Filtrem les paraules segon el nombre de vegades que surt en els blogs\n",
      "def filtrar_por_porcentaje(df,words,min_prob,max_prob):\n",
      "    num_blogs=count_blogs(df)\n",
      "    filtradas=[]\n",
      "    for word in words:\n",
      "        prob=float( words[word]['n_blogs'])/float(num_blogs)\n",
      "        if(prob>=min_prob and prob<=max_prob): # mirem si la paraula ha aparaescut m\u00e9s del percentatges seleccionats i en cas afirmatiu la afegin  a la llista\n",
      "           filtradas.append(word)\n",
      "    return filtradas\n",
      "    \n",
      "\n",
      "#Cacula les N parules m\u00e9s representativa de cada partit pol\u00edtic.\n",
      "def topNwords(df,words_partits,N):\n",
      "    min_prob=0.1 # Definim el porcentatge m\u00ednim d'aparici\u00f3 d'una paraula per a ser considerada\n",
      "    max_prob=0.5 # Definim el porcentatge m\u00e0xim d'aparici\u00f3 d'una paraula per a ser considerada\n",
      "    valid_words=filtrar_por_porcentaje(df,words,min_prob,max_prob) # Agfem el diccionari amb les paraules filtrades\n",
      "    top_words={}\n",
      "    # seleccionem el subjocunt per a cadascun dels partits\n",
      "    for partit in words_partits:\n",
      "        cont=0\n",
      "        selected_words=[]\n",
      "        d=words_partits[partit].items()\n",
      "        d.sort(key=lambda x: x[1][\"freq\"]) # ordenem les paraules tenint el compte la freq\u00fc\u00e8ncia\n",
      "        d.reverse()\n",
      "        for i in range(len(d)): # Anem afegint paraules fins arribar a l\u00edmit N\n",
      "            if d[i][0]  in  valid_words:\n",
      "                cont =cont+1\n",
      "                if cont>N:\n",
      "                    break\n",
      "                selected_words.append(d[i][0])               \n",
      "        top_words[partit]=selected_words\n",
      "    return top_words\n",
      "\n",
      "N=10\n",
      "words_partits= count_words_party(df,data_blogs)\n",
      "print topNwords(df,words_partits,N)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "ename": "TypeError",
       "evalue": "'int' object has no attribute '__getitem__'",
       "output_type": "pyerr",
       "traceback": [
        "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
        "\u001b[1;32m<ipython-input-38-3c8d7fcee762>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m     34\u001b[0m \u001b[0mN\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m10\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     35\u001b[0m \u001b[0mwords_partits\u001b[0m\u001b[1;33m=\u001b[0m \u001b[0mcount_words\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdf\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mdata_blogs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 36\u001b[1;33m \u001b[1;32mprint\u001b[0m \u001b[0mtopNwords\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdf\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mwords_partits\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mN\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
        "\u001b[1;32m<ipython-input-38-3c8d7fcee762>\u001b[0m in \u001b[0;36mtopNwords\u001b[1;34m(df, words, N)\u001b[0m\n\u001b[0;32m     21\u001b[0m         \u001b[0mselected_words\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     22\u001b[0m         \u001b[0md\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mwords_partits\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mpartit\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mitems\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 23\u001b[1;33m         \u001b[0md\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msort\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mlambda\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m\"freq\"\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;31m# ordenem les paraules tenint el compte la freq\u00fc\u00e8ncia\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     24\u001b[0m         \u001b[0md\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mreverse\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     25\u001b[0m         \u001b[1;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0md\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m \u001b[1;31m# Anem afegint paraules fins arribar a l\u00edmit N\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
        "\u001b[1;32m<ipython-input-38-3c8d7fcee762>\u001b[0m in \u001b[0;36m<lambda>\u001b[1;34m(x)\u001b[0m\n\u001b[0;32m     21\u001b[0m         \u001b[0mselected_words\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     22\u001b[0m         \u001b[0md\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mwords_partits\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mpartit\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mitems\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 23\u001b[1;33m         \u001b[0md\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msort\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mkey\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mlambda\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m\"freq\"\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;31m# ordenem les paraules tenint el compte la freq\u00fc\u00e8ncia\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     24\u001b[0m         \u001b[0md\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mreverse\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     25\u001b[0m         \u001b[1;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0md\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m \u001b[1;31m# Anem afegint paraules fins arribar a l\u00edmit N\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
        "\u001b[1;31mTypeError\u001b[0m: 'int' object has no attribute '__getitem__'"
       ]
      }
     ],
     "prompt_number": 38
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "<b>Exercici 6</b>: Creeu el vector de caracter\u00edstiques necessari per a fer l\u2019entrenament del Na\u00efve Bayes (funci\u00f3 <b>create_features()</b>)."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# Crea el vector de caracter\u00edsticas necesari per a l'entrenament del classificador Naive Bayes\n",
      "# selected_words: ha de ser el diccionari que obteniu amb la funci\u00f3 topNWords amb les paraules seleccionades a partir de la funci\u00f3 TopNwords\n",
      "# data_blogs : cont\u00e9 el diccionari amb la informaci\u00f3 de cada blog\n",
      "# Rertorna un diccionari que cont\u00e9 un np.array amb el vector de caracter\u00edstiques (mireu l'exemple de l'enunciat)\n",
      "\n",
      "def create_features(data_blogs,top_words):\n",
      "    dict_feat_vector={}\n",
      "    selected_words =  list(set([word for item in top_words for word in top_words[item]]))\n",
      "    for blog in data_blogs:\n",
      "        dict_feat_vector[blog]=np.zeros(len(selected_words))\n",
      "        for i in range(len(selected_words)):\n",
      "            if(data_blogs[blog][1].has_key(selected_words[i])):\n",
      "                dict_feat_vector[blog][i]=dict_feat_vector[blog][i]+1\n",
      "    return dict_feat_vector\n",
      "\n",
      "top_words=topNwords(df,words_partits,N)\n",
      "feat_vector = create_features(data_blogs,top_words)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "ename": "NameError",
       "evalue": "name 'topNwords' is not defined",
       "output_type": "pyerr",
       "traceback": [
        "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
        "\u001b[1;32m<ipython-input-20-8cfb20f2c6ac>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m     14\u001b[0m     \u001b[1;32mreturn\u001b[0m \u001b[0mdict_feat_vector\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     15\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 16\u001b[1;33m \u001b[0mtop_words\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mtopNwords\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdf\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mwords_partits\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mN\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     17\u001b[0m \u001b[0mfeat_vector\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mcreate_features\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata_blogs\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mtop_words\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
        "\u001b[1;31mNameError\u001b[0m: name 'topNwords' is not defined"
       ]
      }
     ],
     "prompt_number": 20
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "<b>Exercici 7</b>: Implementeu la funci\u00f3 d'aprenentatge del classificador Na\u00efve Bayes (funci\u00f3 <b>naive_bayes_learn()</b>).  La funci\u00f3 ha de mostrar el resultat obtingut per pantall\n",
      "<br>\n",
      "<b> * L'error d'entrenament</b>\n",
      "L'error d'entrenament es troba calculant el percentatge d'errors que s'obtenen quan es fa el testeig amb les mateixes dades utilizades per fer entrenament (aprenentatge). Aquest error es un valor molt optimista de com funcionar\u00e0 el clasificador i mai s'ha de prendre com a mesura per comparar clasificadors.\n",
      "<br>"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "#Funci\u00f3 de training\n",
      "def learn_naive_bayes(df,featVector,llista_partits):\n",
      "    # ********************** TRAINING STEP*****************************************\n",
      "    num_paraules=len(featVector[featVector.keys()[0]]) # Mirem la longitud del nostre vector de caracter\u00edstiques\n",
      "    \n",
      "    # incialitzaci\u00f3 dels diccionaris que utilizarem\n",
      "    freq_word={} \n",
      "    freq_word=np.zeros(num_paraules)\n",
      "    freq_word_p={}\n",
      "    n_blogs_partit={}\n",
      "    # Iniclializem el diccionari\n",
      "    for partit in llista_partits:\n",
      "        freq_word_p[partit]=np.zeros(num_paraules)\n",
      "        n_blogs_partit[partit]=0\n",
      "            \n",
      "    # Calculem quant cops ha aparescut cada paraula dins cadascun dels partits politics\n",
      "    # iterem per blog\n",
      "    for blog in featVector:\n",
      "        cont=0\n",
      "        p_class=df.ix[int(blog)]['partit_politic'] # partit politic del blog\n",
      "        n_blogs_partit[p_class]+=1\n",
      "        # iterem per cada element del vector, \u00e9s a dir, per a cada paraula\n",
      "        for word in featVector[blog]:\n",
      "            freq_word_p[p_class][cont]=freq_word_p[p_class][cont]+word\n",
      "            cont+=1\n",
      "    # C\u00e0lcul de les probabilitats\n",
      "    prob_word_p={}\n",
      "    for partit in llista_partits:\n",
      "        prob_word_p[partit]=(freq_word_p[partit] +1) / (n_blogs_partit[partit] + len(llista_partits))\n",
      "        \n",
      "    return prob_word_p\n",
      "#Funci\u00f3 de test \n",
      "def test_naive_bayes(df,featVector,prob_word_p,llista_partits):\n",
      "    resultats={} # Incializem un diccionari per controlar els encerts\n",
      "    for partit in llista_partits:\n",
      "        resultats[partit]={}\n",
      "        resultats[partit]['encerts']=0\n",
      "        resultats[partit]['num_blogs']=0\n",
      "\n",
      "    for blog in featVector:\n",
      "        resultat_blog=[]\n",
      "        # MIREM EL RESULTAT PER CADA POSSIBLE CLASSE\n",
      "        for partit in llista_partits:\n",
      "            score=0\n",
      "            i=0\n",
      "            for item in featVector[blog]:\n",
      "                if item==1:\n",
      "                    score+=np.log(prob_word_p[partit][i])\n",
      "                else:\n",
      "                    score+=np.log(1-prob_word_p[partit][i])\n",
      "                i+=1\n",
      "            resultat_blog.append( (score,partit))\n",
      "            \n",
      "        # Comparem si la classe que ha donat m\u00e0xima probabilitat \u00e9s la real\n",
      "        p_class=df.ix[int(blog)]['partit_politic'] # partit politic del blog\n",
      "        if( max(resultat_blog)[1]==p_class):\n",
      "            resultats[p_class]['encerts']+=1\n",
      "        resultats[p_class]['num_blogs']+=1\n",
      "    return resultats\n",
      "        \n",
      "        \n",
      "\n",
      "#M\u00e8todo que implementa el clasificador Naive_Bayes.Ha de mostrar el resultat obtingut per pantalla\n",
      "def naive_bayes(df,featVector):\n",
      "    llista_partits=list(set(df['partit_politic'])) # Mirem quants partits tenim\n",
      "    # ********************** TRAINING STEP*****************************************\n",
      "    prob_word_p = learn_naive_bayes(df,featVector,llista_partits)\n",
      "    # ********************** TEST STEP*****************************************\n",
      "    resultats = test_naive_bayes(df,featVector,prob_word_p,llista_partits)\n",
      "    # MOSTREM ELS RESULTATS OBTINGUTS\n",
      "    for item in resultats:\n",
      "        print \"% ENCERTS  \", item, ': ', 100* float(resultats[item]['encerts'])/resultats[item]['num_blogs'], resultats[item]['encerts'], '/', resultats[item]['num_blogs']\n",
      "    \n",
      "    encertsTotals=0\n",
      "    for item in resultats:\n",
      "        encertsTotals+=resultats[item]['encerts']\n",
      "    print \"% ERROR GLOBAL: \", 100 -100* float(encertsTotals)/len(featVector)\n",
      "    \n",
      "naive_bayes(df,feat_vector)\n"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "% ENCERTS   PSC :  58.8235294118 20 / 34\n",
        "% ENCERTS   ICV :  72.0 18 / 25\n",
        "% ENCERTS   CIU :  71.875 23 / 32\n",
        "% ENCERTS   ERC :  82.7586206897 24 / 29\n",
        "% ERROR GLOBAL:  29.1666666667\n"
       ]
      }
     ],
     "prompt_number": 136
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "<b>Exercici 8: </b> Indiqueu l'error de generalitzaci\u00f3 fent servir Leave-one-out (funci\u00f3 <b>leave1out ()</b> )\n",
      "\n",
      "<b> * Aproximaci\u00f3 a l'error de generalitzaci\u00f3 fent servir Leave-one-out</b>\n",
      "Una bona forma de veure com funcionaria el nostre classificador davant de dades sobre les quals no s'ha entrenat \u00e9s fer servir l'estrat\u00e8gia leave-one-out. Aquesta estrat\u00e8gia entrena el classificador amb totes les dades d'entrenament menys amb una i fa el testeig sobre la dada que hem excl\u00f2s de l'entrenament. Aquest proc\u00e9s d'exclusi\u00f3 es repeteix per cadascuna de les dades d'entrenament. El percentatge d'errors fent servir aquesta estrat\u00e8gia permet comparar classificadors."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "#M\u00e8tode per avaluar el classificador mitjan\u00e7ant la t\u00e8cnica leave-one-out.  Ha de mostrar el resultat obtingut per pantalla\n",
      "def leave1out(df,featVector):\n",
      "    \n",
      "    llista_partits=list(set(df['partit_politic'])) # Mirem quants partits tenim\n",
      "    resultats={} # Incializem un diccionari per controlar els encerts    \n",
      "    for partit in llista_partits:\n",
      "        resultats[partit]={}\n",
      "        resultats[partit]['encerts']=0\n",
      "        resultats[partit]['num_blogs']=0\n",
      "        \n",
      "        \n",
      "    for item in featVector:\n",
      "        trainfeatVector=featVector.copy() # creem un diccionari per les dades de train\n",
      "        del trainfeatVector[item] # eliminem un element de les dades de train que utilizarem de test\n",
      "        testfeatVector={} # creem un diccionari per les dades de test\n",
      "        testfeatVector[item]=featVector[item]\n",
      "        llista_partits=list(set(df['partit_politic'])) # Mirem quants partits tenim\n",
      "        # ********************** TRAINING STEP*****************************************\n",
      "        prob_word_p = learn_naive_bayes(df,trainfeatVector,llista_partits) # creem el classificador\n",
      "        # ********************** TEST STEP*****************************************\n",
      "        res = test_naive_bayes(df,testfeatVector,prob_word_p,llista_partits) # avaluem el classificador amb la dada de test\n",
      "        resultats[df.ix[item]['partit_politic']]['num_blogs']+=1\n",
      "        resultats[df.ix[item]['partit_politic']]['encerts']+=res[df.ix[item]['partit_politic']]['encerts']\n",
      "    \n",
      "    # MOSTREM ELS RESULTATS OBTINGUTS    \n",
      "    for item in resultats:\n",
      "        print \"% ENCERTS  \", item, ': ', 100* float(resultats[item]['encerts'])/resultats[item]['num_blogs'], resultats[item]['encerts'], '/', resultats[item]['num_blogs']\n",
      "    \n",
      "    encertsTotals=0\n",
      "    for item in resultats:\n",
      "        encertsTotals+=resultats[item]['encerts']\n",
      "    print \"% ERROR GLOBAL: \", 100 -100* float(encertsTotals)/len(featVector)\n",
      "    \n",
      "    \n",
      "leave1out(df,feat_vector)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "% ENCERTS   PSC :  40.0 12 / 30\n",
        "% ENCERTS   ICV :  56.0 14 / 25\n",
        "% ENCERTS   CIU :  71.875 23 / 32\n",
        "% ENCERTS   ERC :  82.7586206897 24 / 29\n",
        "% ERROR GLOBAL:  37.0689655172\n"
       ]
      }
     ],
     "prompt_number": 88
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Definici\u00f3 de la funci\u00f3 p"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# Main. Se hacen las llamadas a las diversas funciones para la correcta ejecucion del programa    \n",
      "def main():\n",
      "    \n",
      "    unames = ['id_blog', 'partit_politic', 'nom', 'url']\n",
      "    df = pd.read_table('blogs.dat',sep='::', header=None, names=unames)\n",
      "\n",
      "    # EXEMPLE DE COM BAIXR D'UN CONJUNT DE BLOGS\n",
      "    data_blogs,invalid_blogs=download_text(df)\n",
      "    # EXEMPLE DE COM ELIMINAR AQUELLS BLOGS QUE NO S'HA POGUT ACCEDIR\n",
      "    df=df.drop(invalid_blogs)\n",
      "    #agafem el conjunt de paraules que utilziarem\n",
      "    N = 15 # Aquest parametre el podem canviar i fer proves per avaluar quin \u00e9s el millor valor\n",
      "    top_words=topNwords(df,words_partits,N)\n",
      "        \n",
      "    \n",
      "    #creem el vector de caracter\u00edstiques\n",
      "    feature_vectors = create_features(data_blogs,top_words)\n",
      "    \n",
      "    print \"Naive Bayes Error\"\n",
      "    #Creem i avaluem el cassificador amb les mateixes dades d'entranament \n",
      "    naive_bayes(df,feature_vectors) \n",
      "    \n",
      "    print \"\\n\\nLeave One Out Error\"\n",
      "    #Avaluem el classificador mitjan\u00e7ant la t\u00e8cnica de leave-lone-out\n",
      "    leave1out(df, feature_vectors)\n",
      "    \n",
      " \n",
      "\n"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 140
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "main()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "Naive Bayes Error\n",
        "% ENCERTS  "
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        " PSC :  58.8235294118 20 / 34\n",
        "% ENCERTS   ICV :  76.0 19 / 25\n",
        "% ENCERTS   CIU :  71.875 23 / 32\n",
        "% ENCERTS   ERC :  82.7586206897 24 / 29\n",
        "% ERROR GLOBAL:  28.3333333333\n",
        "\n",
        "\n",
        "Leave One Out Error\n",
        "% ENCERTS  "
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        " PSC :  47.0588235294 16 / 34\n",
        "% ENCERTS   ICV :  56.0 14 / 25\n",
        "% ENCERTS   CIU :  71.875 23 / 32\n",
        "% ENCERTS   ERC :  82.7586206897 24 / 29\n",
        "% ERROR GLOBAL:  35.8333333333\n"
       ]
      }
     ],
     "prompt_number": 141
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [],
     "language": "python",
     "metadata": {},
     "outputs": []
    }
   ],
   "metadata": {}
  }
 ]
}